/*
 * *******************************************************
 *
 * 作者：hzy
 *
 * 开源地址：https://gitee.com/hzy6
 *
 * *******************************************************
 */

namespace HZY.Framework.Repository.EntityFramework.Repositories.Impl;

/// <summary>
/// 基础仓储 Crud 实现
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TDbContext"></typeparam>
public abstract class RepositoryBaseImpl<T, TDbContext> : QueryRepositoryImpl<T, TDbContext>, IRepositoryBase<T>
    where T : class, new()
    where TDbContext : DbContext
{
    /// <summary>
    /// 基础仓储 Crud 实现
    /// </summary>
    /// <param name="dbContext"></param>
    /// <param name="serviceProvider"></param>
    /// <param name="filter"></param>
    protected RepositoryBaseImpl(TDbContext dbContext, IServiceProvider serviceProvider,
        Expression<Func<T, bool>>? filter = null)
        : base(dbContext, serviceProvider, filter)
    {
    }

    #region 插入

    /// <summary>
    /// 设置默认值根据 tableId 特性
    /// </summary>
    /// <param name="modelList"></param>
    private void SetDefaultValueByTableId(IEnumerable<T> modelList)
    {
        using var serviceScope = RepositoryEntityFrameworkExtensions.Host?.Services.CreateScope();

        foreach (var item in modelList)
        {
            TableIdAttribute.HandleByEntity(item, serviceScope?.ServiceProvider ?? ServiceProvider);
        }
    }

    /// <summary>
    /// 插入
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    public virtual T Insert(T model, params string[]? ignorePropertyNames)
    {
        SetDefaultValueByTableId([model]);

        var entry = UnitOfWork.DbSet<T>().Add(model);

        if (ignorePropertyNames is { Length: > 0 })
        {
            // 忽略修改
            foreach (var item in ignorePropertyNames)
            {
                entry.Property(item).IsModified = false;
            }
        }

        UnitOfWork.SaveChanges();
        return model;
    }

    /// <summary>
    /// 插入 批量
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public virtual int InsertRange(IEnumerable<T> model)
    {
        var enumerable = model as T[] ?? model.ToArray();

        SetDefaultValueByTableId([.. enumerable]);

        if (enumerable.Length <= 0)
        {
            return 0;
        }

        UnitOfWork.DbSet<T>().AddRange(enumerable);
        return UnitOfWork.SaveChanges();
    }

    /// <summary>
    /// 插入
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    public virtual async Task<T> InsertAsync(T model, params string[]? ignorePropertyNames)
    {
        SetDefaultValueByTableId([model]);

        var entry = await UnitOfWork.DbSet<T>().AddAsync(model);

        if (ignorePropertyNames is { Length: > 0 })
        {
            // 忽略修改
            foreach (var item in ignorePropertyNames)
            {
                entry.Property(item).IsModified = false;
            }
        }

        await UnitOfWork.SaveChangesAsync();

        return model;
    }

    /// <summary>
    /// 插入 批量
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public virtual async Task<int> InsertRangeAsync(IEnumerable<T> model)
    {
        var enumerable = model as T[] ?? model.ToArray();
        SetDefaultValueByTableId([.. enumerable]);

        if (enumerable.Length <= 0)
        {
            return 0;
        }

        await UnitOfWork.DbSet<T>().AddRangeAsync(enumerable);
        return await UnitOfWork.SaveChangesAsync();
    }

    /// <summary>
    /// 批量插入 - freeSql 批量插入 
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <param name="valuesLimitDefault"></param>
    /// <param name="parameterLimitDefault"></param>
    /// <returns></returns>
    public int InsertBatchByFreeSql(IEnumerable<T> model, Func<string, string>? asTableName = null,
        bool autoTransaction = false, int? valuesLimitDefault = null, int? parameterLimitDefault = null)
    {
        var valuesLimit = 500;
        var parameterLimit = 999;

        if (Context.Database.IsMySql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsNpgsql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsSqlServer())
        {
            valuesLimit = 1000;
            parameterLimit = 2100;
        }

        if (Context.Database.IsOracle())
        {
            valuesLimit = 500;
            parameterLimit = 999;
        }

        if (valuesLimitDefault is not null)
        {
            valuesLimit = valuesLimitDefault.Value;
        }

        if (parameterLimitDefault is not null)
        {
            parameterLimit = parameterLimitDefault.Value;
        }

        var enumerable = model as T[] ?? model.ToArray();
        SetDefaultValueByTableId([..enumerable]);

        var insert = UnitOfWork.FreeSqlOrm.Insert<T>();

        if (asTableName is not null)
        {
            insert.AsTable(asTableName);
        }

        return insert
            .BatchOptions(valuesLimit, parameterLimit, autoTransaction)
            .AppendData(enumerable)
            .ExecuteAffrows();
    }

    /// <summary>
    /// 批量插入 - freeSql 批量插入 
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <param name="valuesLimitDefault"></param>
    /// <param name="parameterLimitDefault"></param>
    /// <returns></returns>
    public Task<int> InsertBatchByFreeSqlAsync(IEnumerable<T> model, Func<string, string>? asTableName = null,
        bool autoTransaction = false, int? valuesLimitDefault = null, int? parameterLimitDefault = null)
    {
        var valuesLimit = 500;
        var parameterLimit = 999;

        if (Context.Database.IsMySql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsNpgsql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsSqlServer())
        {
            valuesLimit = 1000;
            parameterLimit = 2100;
        }

        if (Context.Database.IsOracle())
        {
            valuesLimit = 500;
            parameterLimit = 999;
        }

        if (valuesLimitDefault is not null)
        {
            valuesLimit = valuesLimitDefault.Value;
        }

        if (parameterLimitDefault is not null)
        {
            parameterLimit = parameterLimitDefault.Value;
        }

        var enumerable = model as T[] ?? model.ToArray();
        SetDefaultValueByTableId([..enumerable]);

        var insert = UnitOfWork.FreeSqlOrm.Insert<T>();

        if (asTableName is not null)
        {
            insert.AsTable(asTableName);
        }

        return insert
            .BatchOptions(valuesLimit, parameterLimit, autoTransaction)
            .AppendData(enumerable)
            .ExecuteAffrowsAsync();
    }

    #endregion

    #region 更新

    /// <summary>
    /// 更新
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    public virtual int Update(T model, params string[]? ignorePropertyNames)
    {
        var entry = UnitOfWork.DbSet<T>().Update(model);

        if (ignorePropertyNames is not { Length: > 0 })
        {
            return UnitOfWork.SaveChanges();
        }

        // 忽略修改
        foreach (var item in ignorePropertyNames)
        {
            entry.Property(item).IsModified = false;
        }

        return UnitOfWork.SaveChanges();
    }

    /// <summary>
    /// 根据实体id更新数据
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual int UpdateById(T model, params string[]? ignorePropertyNames)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var value = KeyPropertyInfo.GetValue(model);
        var oldModel = FindById(value);

        if (oldModel == null)
        {
            return 0;
        }

        return Update(oldModel, model, ignorePropertyNames);
    }

    /// <summary>
    /// 更新，通过原模型 修改为新模型 , 请不要关闭全局跟踪会导致无法跟踪字段变化去做部分字段更新操作
    /// </summary>
    /// <param name="oldModel"></param>
    /// <param name="newModel"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    public virtual int Update(T oldModel, T newModel, params string[]? ignorePropertyNames)
    {
        var trackingBehavior = Context.ChangeTracker.QueryTrackingBehavior;
        // 如果全局跟踪实体对象，则走 savechange
        if (trackingBehavior == QueryTrackingBehavior.TrackAll)
        {
            var entry = UnitOfWork.DbSet<T>().Entry(oldModel);
            entry.CurrentValues.SetValues(newModel);

            if (ignorePropertyNames is not { Length: > 0 })
            {
                return UnitOfWork.SaveChanges();
            }

            // 忽略修改
            foreach (var item in ignorePropertyNames)
            {
                entry.Property(item).IsModified = false;
            }

            return UnitOfWork.SaveChanges();
        }

        // 获取 logger
        var logger = Context.GetService<ILogger<RepositoryBaseImpl<T, TDbContext>>>();
        logger.LogWarning("您关闭了全局跟踪，将无法使用忽略，或者部分字段更新的功能！将自动切换到全量字段更新！");

        return Update(newModel, ignorePropertyNames);
    }

    /// <summary>
    /// 更新 批量
    /// </summary>
    /// <param name="models"></param>
    /// <returns></returns>
    public virtual int UpdateRange(IEnumerable<T> models)
    {
        var enumerable = models as T[] ?? models.ToArray();
        if (enumerable.Length <= 0)
        {
            return 0;
        }

        UnitOfWork.DbSet<T>().UpdateRange(enumerable);

        return UnitOfWork.SaveChanges();
    }

    /// <summary>
    /// 更新 批量
    /// </summary>
    /// <param name="models"></param>
    /// <returns></returns>
    public virtual int UpdateRangeById(IEnumerable<T> models)
    {
        var enumerable = models as T[] ?? models.ToArray();
        if (enumerable.Length <= 0)
        {
            return 0;
        }

        if (KeyPropertyInfo is null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var keyList = new List<object>();
        foreach (var model in enumerable)
        {
            var value = KeyPropertyInfo.GetValue(model);
            if (value is null)
            {
                continue;
            }

            // 将 key 值持久化到集合中
            keyList.Add(value);
        }

        // 将 key 集合中的 值 去数据库查询
        // 组装 in 语句
        List<T> oldModelList = [];
        if (keyList.Count > 0)
        {
            var query = this.GetKeyContainsExpression(keyList);
            oldModelList = ToList(query);
        }

        var newUpdateList = new List<T>();
        // 检测更新中的 id 是否在数据库中存在
        foreach (var updateModel in enumerable)
        {
            var oldModel = oldModelList.Find(w =>
            {
                var keyValue = KeyPropertyInfo.GetValue(w) ?? throw new Exception(" 读取 就数据中的 key 值异常");
                return keyValue.Equals(KeyPropertyInfo.GetValue(updateModel));
            });

            if (oldModel is null)
            {
                continue;
            }

            var entry = UnitOfWork.DbSet<T>().Entry(oldModel);
            entry.CurrentValues.SetValues(updateModel);
            newUpdateList.Add(oldModel);
        }

        return UpdateRange(newUpdateList);
    }

    /// <summary>
    /// 更新部分字段 根据where 条件
    /// </summary>
    /// <param name="setPropertyCalls"></param>
    /// <param name="where"></param>
    /// <returns></returns>
    public virtual int UpdateBulk(Expression<Func<SetPropertyCalls<T>, SetPropertyCalls<T>>> setPropertyCalls,
        Expression<Func<T, bool>> where)
    {
        return Select.Where(where).ExecuteUpdate(setPropertyCalls);
    }

    /// <summary>
    /// 更新
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    public virtual Task<int> UpdateAsync(T model, params string[]? ignorePropertyNames)
    {
        var entry = UnitOfWork.DbSet<T>().Update(model);

        if (ignorePropertyNames is not { Length: > 0 })
        {
            return UnitOfWork.SaveChangesAsync();
        }

        // 忽略修改
        foreach (var item in ignorePropertyNames)
        {
            entry.Property(item).IsModified = false;
        }

        return UnitOfWork.SaveChangesAsync();
    }

    /// <summary>
    /// 根据实体id更新数据
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual async Task<int> UpdateByIdAsync(T model, params string[]? ignorePropertyNames)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var value = KeyPropertyInfo.GetValue(model);

        var oldModel = await Select.FirstOrDefaultAsync(GetKeyEqualExpression(value));
        if (oldModel == null)
        {
            return 0;
        }

        return await UpdateAsync(oldModel, model, ignorePropertyNames);
    }

    /// <summary>
    /// 更新，通过原模型 修改为新模型 , 请不要关闭全局跟踪会导致无法跟踪字段变化去做部分字段更新操作
    /// </summary>
    /// <param name="oldModel"></param>
    /// <param name="newModel"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    public virtual Task<int> UpdateAsync(T oldModel, T newModel, params string[]? ignorePropertyNames)
    {
        var trackingBehavior = Context.ChangeTracker.QueryTrackingBehavior;
        // 如果全局跟踪实体对象，则走 savechange
        if (trackingBehavior == QueryTrackingBehavior.TrackAll)
        {
            var entry = UnitOfWork.DbSet<T>().Entry(oldModel);
            entry.CurrentValues.SetValues(newModel);

            if (ignorePropertyNames is not { Length: > 0 })
            {
                return UnitOfWork.SaveChangesAsync();
            }

            // 忽略修改
            foreach (var item in ignorePropertyNames)
            {
                entry.Property(item).IsModified = false;
            }

            return UnitOfWork.SaveChangesAsync();
        }

        // 获取 logger
        var logger = Context.GetService<ILogger<RepositoryBaseImpl<T, TDbContext>>>();
        logger.LogWarning("您关闭了全局跟踪，将无法使用忽略，或者部分字段更新的功能！将自动切换到全量字段更新！");

        return UpdateAsync(newModel, ignorePropertyNames);
    }

    /// <summary>
    /// 更新 批量
    /// </summary>
    /// <param name="models"></param>
    /// <returns></returns>
    public virtual Task<int> UpdateRangeAsync(IEnumerable<T> models)
    {
        var enumerable = models as T[] ?? models.ToArray();
        if (enumerable.Length <= 0)
        {
            return Task.FromResult(0);
        }

        UnitOfWork.DbSet<T>().UpdateRange(enumerable);

        return UnitOfWork.SaveChangesAsync();
    }

    /// <summary>
    /// 更新 批量
    /// </summary>
    /// <param name="models"></param>
    /// <returns></returns>
    public virtual async Task<int> UpdateRangeByIdAsync(IEnumerable<T> models)
    {
        var enumerable = models as T[] ?? models.ToArray();
        if (enumerable.Length <= 0)
        {
            return 0;
        }

        if (KeyPropertyInfo is null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var keyList = new List<object>();
        foreach (var model in enumerable)
        {
            var value = KeyPropertyInfo.GetValue(model);
            if (value is null)
            {
                continue;
            }

            // 将 key 值持久化到集合中
            keyList.Add(value);
        }

        // 将 key 集合中的 值 去数据库查询
        // 组装 in 语句
        List<T> oldModelList = [];
        if (keyList.Count > 0)
        {
            var query = this.GetKeyContainsExpression(keyList);
            oldModelList = await ToListAsync(query);
        }

        var newUpdateList = new List<T>();
        // 检测更新中的 id 是否在数据库中存在
        foreach (var updateModel in enumerable)
        {
            var oldModel = oldModelList.Find(w =>
            {
                var keyValue = KeyPropertyInfo.GetValue(w) ?? throw new Exception(" 读取 就数据中的 key 值异常");
                return keyValue.Equals(KeyPropertyInfo.GetValue(updateModel));
            });

            if (oldModel is null)
            {
                continue;
            }

            var entry = UnitOfWork.DbSet<T>().Entry(oldModel);
            entry.CurrentValues.SetValues(updateModel);
            newUpdateList.Add(oldModel);
        }

        return await this.UpdateRangeAsync(newUpdateList);
    }

    /// <summary>
    /// 更新部分字段 根据where 条件
    /// </summary>
    /// <param name="setPropertyCalls"></param>
    /// <param name="where"></param>
    /// <returns></returns>
    public virtual Task<int> UpdateBulkAsync(
        Expression<Func<SetPropertyCalls<T>, SetPropertyCalls<T>>> setPropertyCalls, Expression<Func<T, bool>> where)
    {
        return Select.Where(where).ExecuteUpdateAsync(setPropertyCalls);
    }

    /// <summary>
    /// 批量更新 - freeSql 批量更新 
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <param name="valuesLimitDefault"></param>
    /// <param name="parameterLimitDefault"></param>
    /// <returns></returns>
    public int UpdateBatchByFreeSql(IEnumerable<T> model, Func<string, string>? asTableName = null,
        bool autoTransaction = false, int? valuesLimitDefault = null, int? parameterLimitDefault = null)
    {
        var valuesLimit = 500;
        var parameterLimit = 999;

        if (Context.Database.IsMySql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsNpgsql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsSqlServer())
        {
            valuesLimit = 1000;
            parameterLimit = 2100;
        }

        if (Context.Database.IsOracle())
        {
            valuesLimit = 500;
            parameterLimit = 999;
        }

        if (valuesLimitDefault is not null)
        {
            valuesLimit = valuesLimitDefault.Value;
        }

        if (parameterLimitDefault is not null)
        {
            parameterLimit = parameterLimitDefault.Value;
        }

        var update = UnitOfWork.FreeSqlOrm.Update<T>();

        if (asTableName is not null)
        {
            update.AsTable(asTableName);
        }

        return update
            .BatchOptions(valuesLimit, parameterLimit, autoTransaction)
            .SetSource(model)
            .ExecuteAffrows();
    }

    /// <summary>
    /// 批量更新 - freeSql 批量更新 
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <param name="valuesLimitDefault"></param>
    /// <param name="parameterLimitDefault"></param>
    /// <returns></returns>
    public Task<int> UpdateBatchByFreeSqlAsync(IEnumerable<T> model, Func<string, string>? asTableName = null,
        bool autoTransaction = false, int? valuesLimitDefault = null, int? parameterLimitDefault = null)
    {
        var valuesLimit = 500;
        var parameterLimit = 999;

        if (Context.Database.IsMySql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsNpgsql())
        {
            valuesLimit = 5000;
            parameterLimit = 3000;
        }

        if (Context.Database.IsSqlServer())
        {
            valuesLimit = 1000;
            parameterLimit = 2100;
        }

        if (Context.Database.IsOracle())
        {
            valuesLimit = 500;
            parameterLimit = 999;
        }

        if (valuesLimitDefault is not null)
        {
            valuesLimit = valuesLimitDefault.Value;
        }

        if (parameterLimitDefault is not null)
        {
            parameterLimit = parameterLimitDefault.Value;
        }

        var update = UnitOfWork.FreeSqlOrm.Update<T>();

        if (asTableName is not null)
        {
            update.AsTable(asTableName);
        }

        return update
            .BatchOptions(valuesLimit, parameterLimit, autoTransaction)
            .SetSource(model)
            .ExecuteAffrowsAsync();
    }

    #endregion

    #region 插入或者更新

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改 , 请不要关闭全局跟踪会导致无法跟踪字段变化去做部分字段更新操作
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual T InsertOrUpdate(T model, params string[]? ignorePropertyNames)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var value = KeyPropertyInfo.GetValue(model);

        if (value is null)
        {
            Insert(model, ignorePropertyNames);
            return model;
        }

        if (value is Guid guid && guid == Guid.Empty)
        {
            Insert(model, ignorePropertyNames);
            return model;
        }

        if (value is Guid && (Guid?)value == Guid.Empty)
        {
            Insert(model, ignorePropertyNames);
            return model;
        }

        var oldModel = FindById(value);
        if (oldModel == null)
        {
            Insert(model, ignorePropertyNames);
        }
        else
        {
            Update(oldModel, model, ignorePropertyNames);
        }

        return model;
    }

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改 , 请不要关闭全局跟踪会导致无法跟踪字段变化去做部分字段更新操作
    /// </summary>
    /// <param name="model"></param>
    /// <param name="ignorePropertyNames"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual async Task<T> InsertOrUpdateAsync(T model, params string[]? ignorePropertyNames)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var value = KeyPropertyInfo.GetValue(model);

        if (value is null)
        {
            await InsertAsync(model, ignorePropertyNames);
            return model;
        }

        if (value is Guid guid && guid == Guid.Empty)
        {
            await InsertAsync(model, ignorePropertyNames);
            return model;
        }

        if (value is Guid && (Guid?)value == Guid.Empty)
        {
            await InsertAsync(model, ignorePropertyNames);
            return model;
        }

        var oldModel = await FindByIdAsync(value);
        if (oldModel == null)
        {
            await InsertAsync(model, ignorePropertyNames);
        }
        else
        {
            await UpdateAsync(oldModel, model, ignorePropertyNames);
        }

        return model;
    }

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改
    /// </summary>
    /// <param name="modelList"></param>
    /// <exception cref="ArgumentNullException"></exception>
    /// <returns></returns>
    public int InsertOrUpdateRange(IEnumerable<T> modelList)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var keyList = new List<object>();
        var insertList = new List<T>();
        var updateList = new List<T>();
        foreach (var model in modelList)
        {
            var value = KeyPropertyInfo.GetValue(model);
            if (value is null)
            {
                insertList.Add(model);
                continue;
            }

            if (value is Guid guid && guid == Guid.Empty)
            {
                insertList.Add(model);
                continue;
            }

            if (value is Guid && (Guid?)value == Guid.Empty)
            {
                insertList.Add(model);
                continue;
            }

            // 将 key 值持久化到集合中
            keyList.Add(value);
            updateList.Add(model);
        }

        // 将 key 集合中的 值 去数据库查询
        // 组装 in 语句
        List<T> oldModelList = [];
        if (keyList.Count > 0)
        {
            var query = this.GetKeyContainsExpression(keyList);
            oldModelList = ToList(query);
        }

        var newUpdateList = new List<T>();
        // 检测更新中的 id 是否在数据库中存在
        foreach (var updateModel in updateList)
        {
            var oldModel = oldModelList.Find(w =>
            {
                var keyValue = KeyPropertyInfo.GetValue(w) ?? throw new Exception(" 读取 就数据中的 key 值异常");
                return keyValue.Equals(KeyPropertyInfo.GetValue(updateModel));
            });

            if (oldModel is null)
            {
                insertList.Add(updateModel);
            }
            else
            {
                var entry = UnitOfWork.DbSet<T>().Entry(oldModel);
                entry.CurrentValues.SetValues(updateModel);
                newUpdateList.Add(oldModel);
            }
        }

        SetDefaultValueByTableId(insertList);
        UnitOfWork.DbSet<T>().AddRange(insertList);
        UnitOfWork.DbSet<T>().UpdateRange(newUpdateList);

        return this.UnitOfWork.SaveChanges();
    }

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改
    /// </summary>
    /// <param name="modelList"></param>
    /// <returns></returns>
    public async Task<int> InsertOrUpdateRangeAsync(IEnumerable<T> modelList)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var keyList = new List<object>();
        var insertList = new List<T>();
        var updateList = new List<T>();
        foreach (var model in modelList)
        {
            var value = KeyPropertyInfo.GetValue(model);
            if (value is null)
            {
                insertList.Add(model);
                continue;
            }

            if (value is Guid guid && guid == Guid.Empty)
            {
                insertList.Add(model);
                continue;
            }

            if (value is Guid && (Guid?)value == Guid.Empty)
            {
                insertList.Add(model);
                continue;
            }

            // 将 key 值持久化到集合中
            keyList.Add(value);
            updateList.Add(model);
        }

        // 将 key 集合中的 值 去数据库查询
        // 组装 in 语句
        List<T> oldModelList = [];
        if (keyList.Count > 0)
        {
            var query = this.GetKeyContainsExpression(keyList);
            oldModelList = await ToListAsync(query);
        }

        var newUpdateList = new List<T>();
        // 检测更新中的 id 是否在数据库中存在
        foreach (var updateModel in updateList)
        {
            var oldModel = oldModelList.Find(w =>
            {
                var keyValue = KeyPropertyInfo.GetValue(w) ?? throw new Exception(" 读取 就数据中的 key 值异常");
                return keyValue.Equals(KeyPropertyInfo.GetValue(updateModel));
            });

            if (oldModel is null)
            {
                insertList.Add(updateModel);
            }
            else
            {
                var entry = UnitOfWork.DbSet<T>().Entry(oldModel);
                entry.CurrentValues.SetValues(updateModel);
                newUpdateList.Add(oldModel);
            }
        }

        SetDefaultValueByTableId(insertList);
        await UnitOfWork.DbSet<T>().AddRangeAsync(insertList);
        UnitOfWork.DbSet<T>().UpdateRange(newUpdateList);

        return await this.UnitOfWork.SaveChangesAsync();
    }

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual int InsertOrUpdateByFreeSql(T model, Func<string, string>? asTableName = null,
        bool autoTransaction = false)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var insertOrUpdate = UnitOfWork.FreeSqlOrm.InsertOrUpdate<T>();

        if (asTableName is not null)
        {
            insertOrUpdate.AsTable(asTableName);
        }

        return insertOrUpdate
                .BatchOptions(200, autoTransaction)
                .SetSource(model)
                .ExecuteAffrows()
            ;
    }

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual Task<int> InsertOrUpdateByFreeSqlAsync(IEnumerable<T> model,
        Func<string, string>? asTableName = null, bool autoTransaction = false)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var insertOrUpdate = UnitOfWork.FreeSqlOrm.InsertOrUpdate<T>();

        if (asTableName is not null)
        {
            insertOrUpdate.AsTable(asTableName);
        }

        return insertOrUpdate
                .BatchOptions(200, autoTransaction)
                .SetSource(model)
                .ExecuteAffrowsAsync()
            ;
    }

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual int InsertOrUpdateByFreeSql(IEnumerable<T> model, Func<string, string>? asTableName = null,
        bool autoTransaction = false)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var insertOrUpdate = UnitOfWork.FreeSqlOrm.InsertOrUpdate<T>();

        if (asTableName is not null)
        {
            insertOrUpdate.AsTable(asTableName);
        }

        return insertOrUpdate
                .BatchOptions(200, autoTransaction)
                .SetSource(model)
                .ExecuteAffrows()
            ;
    }

    /// <summary>
    /// 插入或者添加 根据实体 主键判断是否添加还是修改
    /// </summary>
    /// <param name="model"></param>
    /// <param name="asTableName"></param>
    /// <param name="autoTransaction"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public virtual Task<int> InsertOrUpdateByFreeSqlAsync(T model, Func<string, string>? asTableName = null,
        bool autoTransaction = false)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        var insertOrUpdate = UnitOfWork.FreeSqlOrm.InsertOrUpdate<T>();

        if (asTableName is not null)
        {
            insertOrUpdate.AsTable(asTableName);
        }

        return insertOrUpdate
                .BatchOptions(200, autoTransaction)
                .SetSource(model)
                .ExecuteAffrowsAsync()
            ;
    }

    #endregion

    #region 删除

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public virtual int Delete(T model)
    {
        UnitOfWork.DbSet<T>().Remove(model);
        return UnitOfWork.SaveChanges();
    }

    /// <summary>
    /// 删除 批量
    /// </summary>
    /// <param name="models"></param>
    /// <returns></returns>
    public virtual int Delete(IEnumerable<T> models)
    {
        var enumerable = models as T[] ?? models.ToArray();
        if (enumerable.Length <= 0)
        {
            return 0;
        }

        UnitOfWork.DbSet<T>().RemoveRange(enumerable);

        return UnitOfWork.SaveChanges();
    }

    /// <summary>
    /// 删除 根据表达式
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual int Delete(Expression<Func<T, bool>> expWhere)
        => Delete(Select.Where(expWhere).ToList());

    /// <summary>
    /// 删除 根据表达式 直接 生成 delete from table  where 语句操作
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual int DeleteBulk(Expression<Func<T, bool>> expWhere)
    {
        return Select.Where(expWhere).ExecuteDelete();
    }

    /// <summary>
    /// 删除 根据id
    /// </summary>
    /// <param name="key"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual int DeleteById<TKey>(TKey key)
    {
        if (key == null)
        {
            return 0;
        }

        var model = FindById(key);
        if (model == null)
        {
            return 0;
        }

        return Delete(model);
    }

    /// <summary>
    /// 删除 根据 id集合
    /// </summary>
    /// <param name="keys"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual int DeleteByIds<TKey>(List<TKey> keys)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        if (keys.Count <= 0)
        {
            return 0;
        }

        var exp = EntityFrameworkUtil.Contains<T, TKey>(KeyPropertyInfo.Name, keys);
        return Delete(exp);
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public virtual Task<int> DeleteAsync(T model)
    {
        UnitOfWork.DbSet<T>().Remove(model);
        return UnitOfWork.SaveChangesAsync();
    }

    /// <summary>
    /// 删除 批量
    /// </summary>
    /// <param name="models"></param>
    /// <returns></returns>
    public virtual Task<int> DeleteAsync(IEnumerable<T> models)
    {
        var enumerable = models as T[] ?? models.ToArray();
        if (enumerable.Length <= 0)
        {
            return Task.FromResult(0);
        }

        UnitOfWork.DbSet<T>().RemoveRange(enumerable);

        return UnitOfWork.SaveChangesAsync();
    }

    /// <summary>
    /// 删除 根据表达式
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual async Task<int> DeleteAsync(Expression<Func<T, bool>> expWhere)
        => await DeleteAsync(await Select.Where(expWhere).ToListAsync());

    /// <summary>
    /// 删除 根据表达式 直接 生成 delete from table  where 语句操作
    /// </summary>
    /// <param name="expWhere"></param>
    /// <returns></returns>
    public virtual Task<int> DeleteBulkAsync(Expression<Func<T, bool>> expWhere)
    {
        return Select.Where(expWhere).ExecuteDeleteAsync();
    }

    /// <summary>
    /// 删除 根据 id
    /// </summary>
    /// <param name="key"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual async Task<int> DeleteByIdAsync<TKey>(TKey key)
    {
        if (key == null)
        {
            return 0;
        }

        var model = await FindByIdAsync(key);

        if (model == null)
        {
            return 0;
        }

        return await DeleteAsync(model);
    }

    /// <summary>
    /// 删除 根据id集合
    /// </summary>
    /// <param name="keys"></param>
    /// <typeparam name="TKey"></typeparam>
    /// <returns></returns>
    public virtual async Task<int> DeleteByIdsAsync<TKey>(List<TKey> keys)
    {
        if (KeyPropertyInfo == null)
        {
            throw new Exception("模型未设置主键特性标记!");
        }

        if (keys.Count <= 0) return 0;

        var exp = EntityFrameworkUtil.Contains<T, TKey>(KeyPropertyInfo.Name, keys);
        return await DeleteAsync(exp);
    }

    #endregion

    #region 原生 sql 操作 添加、修改、删除

    /// <summary>
    /// 执行sql 返回受影响的行数 insert|update|delete
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual int ExecuteSqlRaw(string sql, params object[] parameters)
    {
        return Context.Database.ExecuteSqlRaw(sql, parameters);
    }

    /// <summary>
    /// 执行sql 返回受影响的行数 insert|update|delete
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual int ExecuteSqlRaw(string sql, IEnumerable<object> parameters)
    {
        return Context.Database.ExecuteSqlRaw(sql, parameters);
    }

    /// <summary>
    /// 执行sql 返回受影响的行数 insert|update|delete
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public virtual Task<int> ExecuteSqlRawAsync(string sql, CancellationToken cancellationToken = default)
    {
        return Context.Database.ExecuteSqlRawAsync(sql, cancellationToken);
    }

    /// <summary>
    /// 执行sql 返回受影响的行数 insert|update|delete
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <returns></returns>
    public virtual Task<int> ExecuteSqlRawAsync(string sql, params object[] parameters)
    {
        return Context.Database.ExecuteSqlRawAsync(sql, parameters);
    }

    /// <summary>
    /// 执行sql 返回受影响的行数 insert|update|delete
    /// </summary>
    /// <param name="sql"></param>
    /// <param name="parameters"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public virtual Task<int> ExecuteSqlRawAsync(string sql, IEnumerable<object> parameters,
        CancellationToken cancellationToken = default)
    {
        return Context.Database.ExecuteSqlRawAsync(sql, parameters, cancellationToken);
    }

    #endregion
}